package com.zyy.jomap;

import com.zyy.jomap.annotation.EnableJoMap;
import com.zyy.jomap.constant.Constant;
import com.zyy.jomap.constant.DebugConstant;
import com.zyy.jomap.resolve.GenerateMapFile;
import com.zyy.jomap.resolve.ResolveJavaParser;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * JoMap的主入口
 * @author zhangyy
 */
@SupportedAnnotationTypes({"com.zyy.jomap.annotation.EnableJoMap"})
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class JoMapProcessor extends AbstractProcessor {

    /** JAVA文件存放路径--绝对路径 **/
    public static String javaDirAbsPath;

    /** 目标项目的绝对路径--用以解析java文件--E:/workspace/projectName/src/main/java/ **/
    public static String projectDirAbsPath;

    /** 项目中配置的存放包的路径 **/
    public static String joMapPackagePath;

    /** 编译环境 **/
    public static ProcessingEnvironment processingEnvironment;


    /** 获取处理器框架组件 */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        processingEnvironment=processingEnv;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment)  {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "==============process execute============!");
        Set<? extends Element> elementSet=roundEnvironment.getElementsAnnotatedWith(EnableJoMap.class);
        for(Element element:elementSet){
            if(element.getKind()== ElementKind.CLASS){
                TypeElement clazzElement=(TypeElement) element;
                EnableJoMap enableJoMap =element.getAnnotation(EnableJoMap.class);
                //主类名称--ProcessApplication--Test
                String simpleName=clazzElement.getSimpleName().toString();
                //主类的包路径（含主类）--com.zyy.process.Test
                String qualifiedName=clazzElement.getQualifiedName().toString();
                String packagePath=qualifiedName.substring(0,qualifiedName.length()-simpleName.length()-1);
                //获取的路径是错误的。--不是项目路径-C:\Users\zhangyiyang\AppData\Local\JetBrains
                //String userDir=System.getProperty("user.dir");
                //获取项目的绝对路径
                String resourceAbsPath=JoMapProcessor.class.getResource(Constant.SLASH).getPath().substring(1);
                resourceAbsPath=resourceAbsPath.substring(0,resourceAbsPath.length()-Constant.TARGET_PATH.length());
                //项目主类（JAVA）的类绝对路径
                String mainClazzAbsPath=resourceAbsPath+Constant.SRC_MAIN_JAVA_PATH+qualifiedName.replace(Constant.DOT,Constant.SLASH)+Constant.DOT+Constant.JAVA_FILE_EXT_NAME;
                mainClazzAbsPath=mainClazzAbsPath.substring(1);
                String mainPackageAbsPath=resourceAbsPath+Constant.SRC_MAIN_JAVA_PATH+packagePath.replace(Constant.DOT,Constant.SLASH);
                printMsg("mainPackageAbsPath",mainPackageAbsPath);
                List<String> javaFileAbsPathList=new ArrayList<>();
                scannerPackage(mainPackageAbsPath,javaFileAbsPathList);
//                for(String javaFileAbsPath:javaFileAbsPathList){
//                    printMsg("scanner file path",javaFileAbsPath);
//                    //resolveJava(javaFileAbsPath);
//                }
                //目标项目的绝对路径
                projectDirAbsPath=resourceAbsPath+Constant.SRC_MAIN_JAVA_PATH;
                //OK
                //解析代码中的JoMap.copyBean/copyList/copyPage表达式，并返回解析后的映射关系
                Map<String, List<String>> varClazzKeyTargetClazzListMap=ResolveJavaParser.resolveJava(javaFileAbsPathList);
                //根据映射关系生成类的copy方法并编译为class
                GenerateMapFile.doGenerateFile(varClazzKeyTargetClazzListMap);
            }

/*
            //匹配import中存在* 下的类解析--OK
            String matchClazz;
            matchClazz= MatchJava.parseClazzPath("com.hoolink.iot.common.server.alarm.*","AlarmBO");

            MatchJava.addBuffer("AlarmBO",matchClazz);

            matchClazz=MatchJava.parseClazzPath("com.hoolink.iot.common.server.*","AlarmConfigItemBO");

            MatchJava.addBuffer("AlarmConfigItemBO",matchClazz);

            matchClazz=MatchJava.parseClazzPath("com.hoolink.protocol.common.*","UUIDUtil");

            MatchJava.addBuffer("UUIDUtil",matchClazz);

            matchClazz=MatchJava.parseClazzPath("com.baomidou.mybatisplus.core.*","IPage");

            MatchJava.addBuffer("IPage",matchClazz);

            matchClazz=MatchJava.parseClazzPath("com.zyy.yjomapdemo.*","ProjectBO");

            MatchJava.addBuffer("ProjectBO",matchClazz);

            MatchJava.printResolveMsg();

 */

        }
        return true;
    }

    /****************************************私有方法***********************************/
    /**
     * 扫描包下的所有文件
     * @param packagePath 包路径--绝对路径
     * @param fileAbsPathList 包下文件路径
     */
    private void scannerPackage(String packagePath, List<String> fileAbsPathList){
        File file=new File(packagePath);
        if(file.isDirectory()){
            //包的情况
            File[] childFileArr=file.listFiles();
            for(File childFile:childFileArr){
                if(childFile.isDirectory()){
                    //目录
                    scannerPackage(childFile.getPath(),fileAbsPathList);
                }else{
                    //文件
                    if(childFile.getName().endsWith(Constant.JAVA_FILE_EXT_NAME)){
                        fileAbsPathList.add(childFile.getPath());
                    }
                }
            }
        }
    }

    /**
     * 获取文件内容
     * @param fileAbsPath
     * @return
     */
    private String readFile(String fileAbsPath){
        Reader reader=null;
        try {
            reader=new FileReader(fileAbsPath);
            int ch=reader.read();
            StringBuffer buffer=new StringBuffer();
            while(ch!=-1){ //读取成功
                buffer.append((char)ch);
                ch=reader.read();
            }
            printMsg("fileContent",buffer.toString());
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(reader!=null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 打印信息
     * @param msg
     */
    public void printMsg(String tip,String msg){
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, tip+">>>>>>>>>>>>>>"+msg);
    }

    public static void sPrintMsg(String tip,String msg){
        if(DebugConstant.DEBUG){
            return;
        }
        processingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, tip+">>>>>>>>>>>>>>"+msg);
    }
}
